package com.nlp.visualization.service.impl.backend;

import com.nlp.visualization.core.lda.process.LDA4News;
import com.nlp.visualization.core.seg.SegmentType;
import com.nlp.visualization.core.seg.filter.SegFilter;
import com.nlp.visualization.crawler.launcher.StartCrawler;
import com.nlp.visualization.crawler.processor.ProcessorUtil;
import com.nlp.visualization.service.backEnd.IThemeManageService;
import com.nlp.visualization.service.news.INewsService;
import com.nlp.visualization.service.news.impl.NewsServiceImpl;
import com.nlp.visualization.utils.PropertyUtil;
import com.nlp.visualization.utils.TimeHelper;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author LXM
 * @Title: ThemeManageServiceImpl
 * @Description: 主题管理的实现类
 * @date 2018/3/5下午3:29
 */
@Service
public class ThemeManageServiceImpl implements IThemeManageService {

    private String basePath = PropertyUtil.getInstance("config").getProperty("lda.base");

    private String originNewsPath = basePath + PropertyUtil.getInstance("config").getProperty("lda.news.origin");

    private String segNewsPath = basePath + PropertyUtil.getInstance("config").getProperty("lda.news.segment");

    private String modelPath = basePath + PropertyUtil.getInstance("config").getProperty("lda.model");

    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

    private Logger logger = LoggerFactory.getLogger(ThemeManageServiceImpl.class);

    public String getOriginNewsPath() {
        return originNewsPath;
    }

    public void setOriginNewsPath(String originNewsPath) {
        this.originNewsPath = originNewsPath;
    }

    public String getSegNewsPath() {
        return segNewsPath;
    }

    public void setSegNewsPath(String segNewsPath) {
        this.segNewsPath = segNewsPath;
    }

    public String getModelPath() {
        return modelPath;
    }

    public void setModelPath(String modelPath) {
        this.modelPath = modelPath;
    }

    public static SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd");

    //    @Autowired
//    INewsService newsService;
    INewsService newsService = new NewsServiceImpl();

    /**
     * 更新新闻数据
     *
     * @param startDate
     * @param endDate
     */
    @Override
    public void updateNewsSpider(String startDate, String endDate, List<String> sites) throws Exception {

        Date start;
        Date end;
        Calendar calendar = Calendar.getInstance();
        try {
            start = sdf.parse(startDate);
            end = sdf.parse(endDate);
            calendar.setTime(start);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("新闻开始日期或结束日期异常，应该为：yyyy-MM-dd格式");
        }
        //两个日期间隔天数
        int days = (int) ((end.getTime() - start.getTime()) / (1000 * 3600 * 24));
        if (days < 0) {
            throw new Exception("开始时间不得早于结束时间");
        }
        for (int i = 0; i < days; i++) {
            logger.info("正在爬取 " + sdf.format(start) + " 的新闻");
            StartCrawler startCrawler = new StartCrawler(sites);
            startCrawler.start(sdf.format(start));
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            start = calendar.getTime();
        }

    }


    /**
     * 执行分词后以文件的形式保存新闻分词后的文本
     *
     * @param jsonFileDir 新闻目录
     * @param textFileDir 分词结果保存目录
     * @param method
     * @param filter
     * @throws IOException
     */
    @Override
    public void executeNewsSeg(File jsonFileDir, File textFileDir, SegmentType method, SegFilter filter) throws Exception {

        File[] files;

        logger.info("为新闻文件目录:" + jsonFileDir.getPath() + "执行分词操作");
        //获取json目录下的所有文件
        try {
            files = jsonFileDir.listFiles();
        } catch (Exception e) {
            logger.error("读取新闻目录下的所有新闻失败");
            e.printStackTrace();
            throw new IOException("读取新闻目录下的所有新闻失败");

        }
        try {
            for (File file : files) {
                if (file.getName().indexOf(".json") != -1)
                    newsService.newsSeg2Text(file, textFileDir, method, filter);
            }
        } catch (Exception e) {
            logger.error("新闻分词部分未知异常");
            e.printStackTrace();
            throw new Exception("新闻分词部分未知异常");


        }

        newsService.newsSeg2Text(jsonFileDir, textFileDir, method, filter);
        logger.info("新闻内容分词完成，保存路径为：" + textFileDir.getPath());

    }


    /**
     * 训练LDA模型并保存到指定的路径
     *
     * @param themeCount
     * @throws IOException
     */
    @Override
    public void trainAndSaveModel(int themeCount) throws IOException {
        logger.info("训练模型中");
        File model = new File(modelPath, time.format(new Date()) + ".model");
        String path = model.getPath();
        LDA4News lda4News = new LDA4News();
        lda4News.trainModel(segNewsPath, path, themeCount);
        logger.info("模型训练完成，保存路径为" + modelPath);
    }

    /**
     * 人工判断主题名称，再按序列存储到文件，下次可以读取这个文件
     *
     * @param themes
     * @param date
     * @throws IOException
     */
    @Override
    public void setThemesName(List<String> themes, String date) throws IOException {

        //将主题名称存储在以yyyy-dd-mm.seq的文件下
        File file = new File(modelPath, date + ".seq");
        String buf = "";
        if (file.exists()) {
            for (String str : themes) {
                buf += str + "\n";
            }
            FileUtils.writeStringToFile(file, buf, "utf-8");
        }
        logger.info("已经主题按照顺序：" + buf + "的顺序存储");
        return;

    }


    public static void main(String[] args) throws Exception {
        //爬虫爬下网站
        ThemeManageServiceImpl themeManageService = new ThemeManageServiceImpl();
//        List<String> list = new ArrayList<>();
//        list.add("sina");
//        Date date = new Date();
//        Calendar calendar = Calendar.getInstance();
//        calendar.setTime(date);
//        calendar.add(Calendar.DAY_OF_WEEK, 1);
//        themeManageService.updateNewsSpider(time.format(date), time.format(calendar.getTime()), list);
        // 分词服务执行新闻分词
        SegFilter.FilterBuilder builder = new SegFilter.FilterBuilder();
        SegFilter filter = builder.enableStopwords(true).enablePunctuation(true).build();
        File newsJsonDir = new File(themeManageService.getOriginNewsPath());
        File newsSegTextDir = new File(themeManageService.getSegNewsPath());
        themeManageService.executeNewsSeg(newsJsonDir, newsSegTextDir, SegmentType.HANLP_CRF, filter);
//        //训练模型部分
        themeManageService.trainAndSaveModel(15);
        LDA4News news = new LDA4News();
        List list = news.inference("/Users/lxm/MyComputer/Projects/NLPVisualizationWebApp/src/main/resources/data/lda/news/segment/1520342995903-0.36198418821981204.txt",
                "/Users/lxm/MyComputer/Projects/NLPVisualizationWebApp/src/main/resources/data/lda/model/model1520343539779.model");
//
//        System.currentTimeMillis();
    }
}
